package com.hz.house.service;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hz.house.bean.entity.MiniProgramCardMsg;
import com.hz.house.common.ThreadPool;
import com.hz.house.config.WxConfig;
import com.hz.house.dao.MarketingMapper;
import com.hz.house.utils.wxutil.WXPayUtil;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class WxgzhBuyHouseService {

	
	private static String WX_GZH_APPID = "wx863509a1fd0f6b1e";
	private static String WX_GZH_SECRET="cd81b978779bdc9245be96ba62760c47";
	
	
	@Autowired
	private WxConfig wxConfig;
	
	@Autowired
	private MarketingMapper mkMapper;
	
	@Resource
	private RestTemplate restTemplate;
	
	@Autowired
	private ThreadPool threadPool;
	
	@Autowired
	private RedisTemplate<String,Object> redis;
	
	private static String WX_GZH_ACCKT_KEY = "wxgzh_acctk";
	
	public String getWxgzhAcctk() {
		
		String tk = (String) this.redis.opsForValue().get(WX_GZH_ACCKT_KEY);
		if(StringUtils.isEmpty(tk)) {
			tk = gzhAcctk();
			if(tk!=null) 
				this.redis.opsForValue().set(WX_GZH_ACCKT_KEY, tk,2,TimeUnit.HOURS);
		}
		return tk;
	}
	
	
	public void updateGzhAcctk() {
		String tk = gzhAcctk();
		if(tk!=null) 
			this.redis.opsForValue().set(WX_GZH_ACCKT_KEY, tk,2,TimeUnit.HOURS);
	}
	
	
	
	private String gzhAcctk() {
		
		String res = this.restTemplate.getForObject("https://api.weixin.qq.com/cgi-bin/token?"
				+ "grant_type=client_credential&appid="+WX_GZH_APPID+"&secret="+WX_GZH_SECRET, String.class);
		log.info("获取微信公众号token结果:"+res);
		JSONObject jo = JSON.parseObject(res);
		String tk = jo.getString("access_token");
		if(tk!=null)
			return tk;
		return null;
	}
	
	/**
	 * 验证微信接口token
	 * @param req
	 * @return
	 */
	public String validateToken(HttpServletRequest req) {
		String echostr = req.getParameter("echostr");
		return echostr;
	}
	
	/**
	 * <p> 微信公众推送的消息回调业务处理
	 * @param req
	 * @return
	 */
	public void handlebuyHouseWxgzhCallBack(HttpServletRequest req) {
		InputStream is= null;
		try {
			is = req.getInputStream();
			byte[] body = IOUtils.toByteArray(is);
			Map<String,String> m = WXPayUtil.xmlToMap(new String(body,"utf-8"));
			log.info("接收到买房好帮手微信公众号消息推送："+JSON.toJSONString(m));
			String msgType = m.get("MsgType");
			if (msgType.equals("text"))
				handleTextMsg(m);
			else if (msgType.equals("event"))
				handleEventMsg(m);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 *<p>处理文本消息，用户发来的文本内容
	 * @param m
	 */
	private void handleTextMsg(Map<String,String> param) {
		String content = param.get("Content");
		if(StringUtils.isEmpty(content)) {
			log.info("用户发送文本消息内无内容!");
			return;
		}
		
		switch(content) {
			case "1":	//标签找房
				handleSendMpCard(param, 
						"标签找房，找房一步到位", 
						"pages/house/tagHouse/main?fm=1", //pagepath
						"xMh0lyH2-99N2ijtTc9xFkxyfokdNekEXnTZ703aT7c");
				break;
			case "2":	//摇号剩余
				handleSendMpCard(param, 
						"这些在售楼盘，不用摇号！！！", 
						"pages/house/allhouse/main?type=rocksresidue&fm=1", //pagepath
						"xMh0lyH2-99N2ijtTc9xFqFb4EUZNz3lzipnD-4_2yo");
				break;
			case "3":	// 资格查询
				handleSendMpCard(param, 
						"你有天府新区的购买资格吗？查一下就知道！", 
						"pages/personal/tools/query/main?fm=1", //pagepath
						"xMh0lyH2-99N2ijtTc9xFp1nDUT2TwGXiMmyVWzlhGs");
				break;
			case "4":	// 落户查询
				handleSendMpCard(param, 
						"积分怎么落户？查一下就清楚！", 
						"pages/personal/tools/residence/main?fm=1", //pagepath
						"xMh0lyH2-99N2ijtTc9xFtXE-Bg5gh3XnPkvdn86gyY");
				break;
			case "5":	//进购房交流群，发送加群二维码图片
				String openId = param.get("FromUserName");
				handleSendImg(openId,
						"xMh0lyH2-99N2ijtTc9xFr75ltzySlrTtz3y-IUZCNw");
				break;
				default:
					log.info("未知的文本内容:"+content);
		}
			
	}
	
	private void handleSendMpCard(Map<String,String> param,String title,String page,String coverId) {
		String openId = param.get("FromUserName");
		Map<String,Object> data = new HashMap<String, Object>();
		data.put("touser", openId);
		data.put("msgtype", "miniprogrampage");
		Map<String,String> card = new HashMap<>();
		card.put("title",title);
		card.put("appid", this.wxConfig.getAppid());
		card.put("pagepath", page);
		card.put("thumb_media_id",coverId);
		data.put("miniprogrampage", card);
		//3、调用发送接口
		String json = JSON.toJSONString(data);
		String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send"
				+ "?access_token="+getWxgzhAcctk();
		String res = doPostSendMsg(json, url);
		System.out.println("发送小程序卡片结果:"+res);
	}
	
	
	/**处理推送的事件消息：*/
	private void handleEventMsg(Map<String,String> m){
		String msgEvent = m.get("Event");
		switch(msgEvent) {
			case "subscribe"://关注事件，有可能是扫码后关注，有可能直接关注
				handleSubscribeEvent(m);
				break;
			case "SCAN"://扫码事件
				handleScanEvent(m, false);
				break;
			case "CLICK"://点击事件
				handleClickEvent(m);
				break;
			default:
		}
	}
	
	
	/**处理点击事件，通过eventKey来识别是什么东西*/
	private void handleClickEvent(Map<String,String> m) {
		String ek = m.get("EventKey");
		String openId = m.get("FromUserName");
		if(StringUtils.isEmpty(ek))
			return;
		switch(ek) {
			case "ADD_GROUP_X001"://加群图片
				handleSendImg(openId, 
						 "xMh0lyH2-99N2ijtTc9xFmRSmDauYrL0DHTyNX1b2Xw");
				break;
			default:
		}
	}
	
	private void handleSubscribeEvent(Map<String,String> m) {
		
		//新用户关注，先发送一波欢迎语
		sendSubscribeWord(m);
		//处理关注事件---获取用户的unionid后与小程序绑定
		bindUserUnionIdOpenid(m);
		//处理如果是扫码进来的各种事件
		String ek = m.get("EventKey");
		if(!StringUtils.isEmpty(ek))
			handleScanEvent(m, true);
	}
	
	//判断ek是不是都是数字
	private static Pattern numberPattern = Pattern.compile("[0-9]*");
	private void handleScanEvent(Map<String,String> m,boolean isFromSubscribe) {
		
		String ek = getEventKeyFromScan(m, isFromSubscribe);
		if(isNumber(ek)) {
			//全是数值的id
			handleSendBuildingZiLiao(ek, m);
			return;
		}
		//处理其他各种类型的扫码事件,如果正确处理了就不往下了，否则视为特殊事件处理
		boolean result  = handleOtherEvents(m,ek);
		if(result)
			return;
		//往下的就是各种特殊扫码事件
		handleSpecialEvents(m,ek);
	}
	
	private void handleSpecialEvents(Map<String,String> param,String ek) {
		switch(ek) {
			case "yaohao_change":
				handleSendMpCard(param, "重磅！摇号规则有变！", 
						"pages/tabBar/home/main?fromShare=true&id=10001664&type=policyNews",
						"xMh0lyH2-99N2ijtTc9xFsn1RDDz0vlx5z7ooEVpx3E");
				break;
			default:
		}
	}
	
	/**处理各种扫码事件，根据ek的特殊标识来识别*/
	private boolean handleOtherEvents(Map<String,String> m,String ek) {
		log.info("处理扫码事件："+ek);
		return false;
	}
	
	private void handleSendBuildingZiLiao(String ek,Map<String,String> param) {
		//1、根据场景ID查询消息体，直接可以发送
		MiniProgramCardMsg cardMsg =  mkMapper.getMiniCardMsg(Integer.parseInt(ek));
		if(cardMsg==null) {
			System.out.println("扫码的sceneid不存在指定消息");
			return;
		}
		//2、调用客服消息回复接口 回复小程序卡片
		handleSendMpCard(param, 
				cardMsg.getTitle(),
				cardMsg.getPageUrl(),
				cardMsg.getMediaId());
	}
	
	
	private boolean isNumber(String ek) {
		return numberPattern.matcher(ek).matches();
	}
 
	private String getEventKeyFromScan(Map<String,String> m,boolean isFromSubscribe) {
		String ek = m.get("EventKey");
		if(isFromSubscribe)
			ek = ek.substring(8);
		return ek;
	}
	
	
	//用固话与本小程序绑定，获取openid
	private void bindUserUnionIdOpenid(Map<String,String> m) {
		
		this.threadPool.runInThreadPool(()->{
			String openId = m.get("FromUserName");
			String userInfo = getWxgzhUserInfo(openId);
			JSONObject u = JSON.parseObject(userInfo);
			String unionid = u.getString("unionid");
			String nickName = u.getString("nickname");
			if (StringUtils.isEmpty(unionid)) {
				log.info("未获取到用户[" + nickName + "]的unionid");
				return;
			}
			//如果又unioid，则进行绑定
			Map<String,Object> x = new HashMap<>();
			x.put("unionid", unionid);
			x.put("openid", openId);
			int index = this.mkMapper.bindUnionidAndWxgzhOpenid(x);
			if(index<1) {
				log.info("用户关注买房好帮手服务号，但是小程序内未授权，没有unionid,绑定openid失败");
				try {
					//授权失败绑定失败的，暂存他们的id到临时表，在小程序授权的时候更新到用户
					this.mkMapper.addBuyHouseWxgzhInfo(x);
				} catch (Exception e) {
				}
			}
		});
		
	}
	
	
	private String getuserInfoUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="
			+ "{token}&openid={openId}&lang=zh_CN";

	private String getWxgzhUserInfo(String openId) {
		Map<String, Object> m = new HashMap<>();
		m.put("openId", openId);
		m.put("token", getWxgzhAcctk());
		String res = this.restTemplate.getForObject(getuserInfoUrl, String.class, m);
		log.info("获取公众号用户的信息:" + res);
		return res;
	}
	
	//发送欢迎语
	private void sendSubscribeWord(Map<String,String> p) {
		
		this.threadPool.runInThreadPool(()->{
			String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token="
					+ getWxgzhAcctk();
			String openid = p.get("FromUserName");
			Map<String, Object> m = new HashMap<>();
			m.put("touser", openid);
			m.put("msgtype", "text");
			Map<String, String> x = new HashMap<>();
			String content = "欢迎来到成都买房帮手！\r\n"+
					" \r\n" + 
					"【标签找房】回复“1”，标签找房，找房一步到位！\r\n" + 
					" \r\n" + 
					"【摇号剩余】回复“2”，这些在售楼盘，不用摇号！\r\n" + 
					" \r\n" + 
					"【资格查询】回复“3”，你有天府新区的购买资格吗？查一下就知道！\r\n" + 
					" \r\n" + 
					"【落户查询】回复“4”，积分怎么落户？查一下就清楚！\r\n" + 
					" \r\n" + 
					"【进购房交流群】回复“5”，2020年最受关注的网红盘消息，一条也不放过！";
			x.put("content", content);
			m.put("text", x);
			String data = JSON.toJSONString(m);
			String res = this.doPostSendMsg(data, url);
			log.info("发送用户关注引导语结果：" + res);
		});
	}
	
 
	private void handleSendImg(String openid,String imgId) {
		Map<String,Object> m = new HashMap<>();
		m.put("touser", openid);
		m.put("msgtype", "image");
		Map<String,Object> x = new HashMap<>();
		x.put("media_id",imgId);
		m.put("image", x);
		String json = JSON.toJSONString(m);
		String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send"
				+ "?access_token="+getWxgzhAcctk();
		 String res = doPostSendMsg(json,url);
		 System.out.println("发送图片结果:"+res);
	}
	
	
	
	/**封装http请求发送post,返回接口的结果 */
	private String doPostSendMsg(String jsonData,String url) {
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		HttpEntity<String> entity = new HttpEntity<String>(jsonData, headers);
		String json = restTemplate.postForObject(url, entity, String.class);
		return json;
	}
	
	
	/**
	 * 		成都买房帮手用户授权后抓取用户的unionid实现绑定小程序内的用户一一对应
	 * @param req 
	 * @return 0 错误重试，1登录小程序后重试，2绑定成功
	 */
	public int wxgzhAuth2Callback(HttpServletRequest req) {
		
		String code = req.getParameter("code");
		log.info("公众号授权code:"+code);
		if(StringUtils.isEmpty(code))
			return 0;
		try {
			//换取网页授权token和公众号的openid，和上面的基础支持token不同
			JSONObject jso = getWebAuthTokenFromTct(code);
			String tk = jso.getString("access_token");
			if(StringUtils.isEmpty(tk))
				return 0;
			String openid = jso.getString("openid");
			if(StringUtils.isEmpty(openid))
				return 0;
			//使用tk和openid调用getUserinfo接口获取unionid
			JSONObject uinfo = this.getWxgzhWebUserInfo(tk, openid);
			String unionId = uinfo.getString("unionid");
			log.info("unionid:"+unionId);
			if(StringUtils.isEmpty(unionId)) {
				log.info("未获取到公众号用户的unionid");
				return 0;
			}
			//直接修改绑定用户表
			Map<String,Object> m = new HashMap<>();
			m.put("unionId", unionId);
			m.put("openid", openid);
			int x = this.mkMapper.bindUnionidAndWxgzhOpenid(m);
			if(x>0)
				return 2;
			return 1;
		} catch (Exception e) {
			e.printStackTrace();
			log.error("绑定用户授权异常",e);
			return 0;
		}
	}
	
	//公众号获取用户信息接口地址，可获取unionid
	private String wxgzhWebGetUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo"
			+ "?access_token={webacctk}&openid={openid}&lang=zh_CN";
	
	/**
	 * 	获取微信公众号用户的unionid
	 * @return
	 */
	private JSONObject getWxgzhWebUserInfo(String tk,String openid) {
		Map<String,Object> m = new HashMap<>();
		m.put("webacctk", tk);
		m.put("openid", openid);
		String res = this.restTemplate.getForObject(this.wxgzhWebGetUserInfoUrl,String.class,m);
		log.info("公众号web获取用户信息unionid接口结果:"+res);
		JSONObject jso = JSON.parseObject(res);
		return jso;
	}
	
	
	
	
	/**公众号web授权获取tk接口url*/
	private String wxgzhWebAcctkUrl = "https://api.weixin.qq.com/sns/oauth2/access_token"
			+ "?appid={appid}&secret={secret}&code={code}&grant_type=authorization_code";

	/**
	 * 	获取网页授权的token调用凭证
	 * @param code
	 * @return
	 */
	private JSONObject getWebAuthTokenFromTct(String code) {
		
		Map<String,Object> m = new HashMap<>();
		m.put("appid",WX_GZH_APPID);
		m.put("secret",WX_GZH_SECRET);
		m.put("code", code);
		String res = this.restTemplate.getForObject(this.wxgzhWebAcctkUrl,String.class,m);
		log.info("公众号web授权token信息接口结果:"+res);
		JSONObject jso = JSON.parseObject(res);
		return jso;
	}
	
	
	
	
}
